package com.ainiyar.springweb.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import javax.crypto.spec.SecretKeySpec;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

/**************************************
 * File Name : JWTUtil
 * Created with : IntelliJ IDEA.
 * Author : 艾尼亚尔·毛拉吾提
 * QQ : 524155792  WeChat : ainiyar0124
 * Created Time : 2024/2/4  13:54
 * Desc :jwt处理类
 ***************************************/
@Data
@Component
@ConfigurationProperties(prefix = "jwt")
public class JWTUtil {
    //密钥
    private String secret="sw";
    // 过期时间 毫秒
    private Long expiration=1800000L;

    public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
        final Claims claims = extractAllClaim(token);
        return claimsResolver.apply(claims);
    }

    private Claims extractAllClaim(String token) {
        return Jwts.parserBuilder().setSigningKey(getSignKey()).build().parseClaimsJws(token).getBody();
    }

    /**
     * 过期时间
     *
     * @param token token
     * @return Long
     */
    public Long extractTime(String token) {
        return Jwts.parserBuilder().setSigningKey(getSignKey()).build().parseClaimsJws(token).getBody().getExpiration().getTime();
    }

    private SecretKeySpec getSignKey() {
        return new SecretKeySpec(secret.repeat(8).getBytes(), "HmacSHA256");
    }

    /**
     * 生成token
     *
     * @param userDetails 用户信息
     * @return String
     */
    public String generateToken(UserDetails userDetails) {
        return generateToken(new HashMap<>(), userDetails.getUsername());
    }

    public String generateToken(Map<String, Object> claims, String userName) {
        return Jwts
                .builder()
                .setClaims(claims)
                .setSubject(userName)
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + expiration))
                .signWith(getSignKey(), SignatureAlgorithm.HS512)
                .compact();
    }

    /**
     * 刷新token
     *
     * @param token       old token
     * @param userName 用户信息
     * @return String
     */
    public String refreshToken(String token, String userName) {
        String refreshedToken;
        try {
            Claims claims = extractAllClaim(token);
            claims.put(Claims.ISSUED_AT, new Date());
            refreshedToken = generateToken(claims, userName);
        } catch (Exception e) {
            refreshedToken = null;
        }
        return refreshedToken;
    }

    /**
     * 根据token获取用户名
     *
     * @param token token
     * @return String
     */
    public String extractUserName(String token) {
        return extractClaim(token, Claims::getSubject);
    }

    /**
     * 验证token
     *
     * @param token       token
     * @param user_name 用户信息
     * @return boolean
     */
    public boolean isTokenValid(String token, String user_name) {
        final String userName = extractUserName(token);
        return (userName.equals(user_name)) && !isTokenExpired(token);
    }

    /**
     * 检查token是否已过期
     *
     * @param token token
     * @return boolean
     */
    public boolean isTokenExpired(String token) {
        return extractTokenExpired(token).before(new Date());
    }

    private Date extractTokenExpired(String token) {
        return extractClaim(token, Claims::getExpiration);
    }
}

